<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2.针对海量数据优化性能-使用点图元优化</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="400" height="400"></canvas>

    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        /**
         * gl-renderer 在 WebGL 底层的基础上进行了一些简单的封装，以便于我们将重点放在提供几何数据、设置变量和编写 Shader 上，不用因为创建 buffer 等细节而分心
         * 第一步: 创建 Renderer 对象
         * 第二步: 创建并启用 WebGL 程序
         * 第三步: 设置 uniform 变量
         * 第四步: 将顶点数据送入缓冲区
         * 第五步: 渲染
        */
        // const canvas = document.querySelector('canvas');
        // const renderer = new GlRenderer(canvas);

        // const vertex = `
        //     attribute vec2 a_vertexPosition;
        //     uniform vec2 uResolution;

        //     varying vec2 vResolution;
        //     varying vec2 vPos;

        //     void main() {
        //         // 设置点图元的大小
        //         gl_PointSize = 0.2 * uResolution.x;
        //         vResolution = uResolution;
        //         vPos = a_vertexPosition;
        //         gl_Position = vec4(a_vertexPosition, 1, 1);
        //     }
        // `;

        // const fragment = `
        //     #ifdef GL_ES
        //     precision highp float;
        //     #endif

        //     varying vec2 vResolution;
        //     varying vec2 vPos;
            
        //     void main() {
        //         // gl_FragCoord
        //         // 当前片元着色器处理的候选片元窗口相对坐标信息，归一化处理
        //         vec2 st = gl_FragCoord.xy / vResolution;
        //         // 将片元着色器的坐标范围对应于顶点着色器的坐标范围
        //         st = 2.0 * st -1.0;
        //         // 计算距离场
        //         float d = distance(st, vPos);
        //         d = 1.0 - smoothstep(0.195, 0.2, d);
        //         gl_FragColor = d * vec4(0, 0, 1, 1);
        //     }
        // `;
        // const program = renderer.compileSync(fragment, vertex);
        // renderer.useProgram(program);

        // renderer.uniforms.uResolution = [canvas.width, canvas.height];
        // renderer.setMeshData({
        //     mode: renderer.gl.POINTS,
        //     positions: [[0, 0]],
        // });

        // renderer.render();

                
        const canvas = document.querySelector('canvas');
        const renderer = new GlRenderer(canvas);

        const vertex = `
            attribute vec2 a_vertexPosition;
            attribute vec4 color;
            attribute float bias;

            uniform float uTime;
            uniform vec2 uResolution;

            varying vec4 vColor;
            varying vec2 vPos;
            varying vec2 vResolution;
            varying float vScale;

            void main() {
                float scale = 0.7 + 0.3 * sin(6.28 * bias + 0.003 * uTime);
                gl_PointSize = 0.05 * uResolution.x * scale;
                vColor = color;
                vPos = a_vertexPosition;
                vResolution = uResolution;
                vScale = scale;
                gl_Position = vec4(a_vertexPosition, 1, 1);
            }
        `;

        const fragment = `
            #ifdef GL_ES
            precision highp float;
            #endif

            varying vec4 vColor;
            varying vec2 vPos;
            varying vec2 vResolution;
            varying float vScale;
            
            void main() {
                vec2 st = gl_FragCoord.xy / vResolution;
                st = 2.0 * st - vec2(1);
                float d = step(distance(vPos, st), 0.05 * vScale);
                gl_FragColor = d * vColor;
            }
        `;
        const program = renderer.compileSync(fragment, vertex);
        renderer.useProgram(program);

        const COUNT = 200000;
        function init() {
            const colors = [];
            const pos = [];
            const bias = [];
            for(let i = 0; i < COUNT; i++) {
                const x = 2 * Math.random() - 1;
                const y = 2 * Math.random() - 1;
                const rotation = 2 * Math.PI * Math.random();

                colors.push([
                Math.random(),
                Math.random(),
                Math.random(),
                1
                ]);

                pos.push([
                2 * Math.random() - 1,
                2 * Math.random() - 1
                ]);

                bias.push(
                Math.random()
                );
            }

            renderer.uniforms.uTime = 0;
            renderer.uniforms.uResolution = [canvas.width, canvas.height];

            renderer.setMeshData({
                mode: renderer.gl.POINTS,
                enableBlend: true,
                positions: pos,
                attributes: {
                color: {data: [...colors]},
                bias: {data: [...bias]},
                },
            });
        }
        init();


        function update(t) {
            renderer.uniforms.uTime = t;
            renderer.render();
            requestAnimationFrame(update);
        }

        update(0);
    </script>
</body>
</html>